package com.ruicar.afs.cloud.afscase.processor.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ruicar.afs.cloud.afscase.approvetask.entity.*;
import com.ruicar.afs.cloud.afscase.approvetask.service.*;
import com.ruicar.afs.cloud.afscase.channel.entity.ChannelBaseInfo;
import com.ruicar.afs.cloud.afscase.channel.entity.ChannelRiskInfo;
import com.ruicar.afs.cloud.afscase.channel.service.ChannelBaseInfoService;
import com.ruicar.afs.cloud.afscase.channel.service.ChannelRiskInfoService;
import com.ruicar.afs.cloud.afscase.common.utils.Const;
import com.ruicar.afs.cloud.afscase.common.utils.DicUtils;
import com.ruicar.afs.cloud.afscase.infomanagement.entity.*;
import com.ruicar.afs.cloud.afscase.infomanagement.service.*;
import com.ruicar.afs.cloud.afscase.mq.approvesendinfo.service.ApproveInformInfoService;
import com.ruicar.afs.cloud.afscase.paramconfmanagement.service.CaseConfParamService;
import com.ruicar.afs.cloud.afscase.processor.enums.NormalSubmitType;
import com.ruicar.afs.cloud.afscase.processor.service.ApproveWorkflowService;
import com.ruicar.afs.cloud.afscase.processor.util.WorkflowTypeUtil;
import com.ruicar.afs.cloud.afscase.processor.vo.NormalBusinessDataVO;
import com.ruicar.afs.cloud.afscase.processor.vo.NormalReformistVO;
import com.ruicar.afs.cloud.afscase.processor.vo.NormalTaskSubmitVO;
import com.ruicar.afs.cloud.afscase.risk.entity.CaseTortoiseApply;
import com.ruicar.afs.cloud.afscase.risk.service.CaseTortoiseApplyService;
import com.ruicar.afs.cloud.afscase.risk.service.CaseTortoiseService;
import com.ruicar.afs.cloud.bizcommon.business.entity.FinCostDetails;
import com.ruicar.afs.cloud.common.core.enums.AfsBaseEnum;
import com.ruicar.afs.cloud.common.core.enums.AfsEnumUtil;
import com.ruicar.afs.cloud.common.core.exception.AfsBaseException;
import com.ruicar.afs.cloud.common.core.security.service.AfsUser;
import com.ruicar.afs.cloud.common.core.security.util.SecurityUtils;
import com.ruicar.afs.cloud.common.modules.afscorebusiness.enums.*;
import com.ruicar.afs.cloud.common.modules.dto.mq.approve.CaseCustAddressDto;
import com.ruicar.afs.cloud.common.modules.dto.mq.approve.CaseCustContactDto;
import com.ruicar.afs.cloud.common.modules.dto.mq.approve.CaseUpdateDetailDto;
import com.ruicar.afs.cloud.common.modules.dto.mq.approve.CaseUpdateInfoSend;
import com.ruicar.afs.cloud.components.datadicsync.DicHelper;
import com.ruicar.afs.cloud.components.datadicsync.dto.DicDataDto;
import com.ruicar.afs.cloud.risk.api.enums.tortoise.GwtTortoiseAntiFraudCallStep;
import com.ruicar.afs.cloud.risk.api.enums.tortoise.GwtTortoiseStartApproveType;
import com.ruicar.afs.cloud.seats.entity.BaseHoliday;
import com.ruicar.afs.cloud.seats.entity.OpraHoliday;
import com.ruicar.afs.cloud.seats.entity.UserCollocation;
import com.ruicar.afs.cloud.seats.service.BaseHolidayService;
import com.ruicar.afs.cloud.seats.service.OpraHolidayService;
import com.ruicar.afs.cloud.seats.service.UserCollocationService;
import com.ruicar.afs.cloud.seats.util.PostStatus;
import com.ruicar.afs.cloud.seats.util.WorkFlag;
import com.ruicar.afs.cloud.workflow.api.dto.flowprocess.WorkFlowResponse;
import com.ruicar.afs.cloud.workflow.api.dto.flowprocess.request.*;
import com.ruicar.afs.cloud.workflow.api.dto.flowprocess.response.FlowCmdBean;
import com.ruicar.afs.cloud.workflow.gwt.service.WorkflowService;
import io.micrometer.core.instrument.util.StringUtils;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;


/**
 * @Description 流程处理
 * @Author Peng_Jinbo
 * @Date 2020/07/17 15:32
 */
@Service
@Slf4j
@AllArgsConstructor
public class ApproveWorkflowServiceImpl implements ApproveWorkflowService {

    private WorkflowService workflowService;
    private CaseBaseInfoService caseBaseInfoService;
    private CaseCostInfoService caseCostInfoService;
    private CaseChannelInfoService caseChannelInfoService;
    private CaseCarInfoService caseCarInfoService;
    private CaseCarStyleDetailService caseCarStyleDetailService;
    private WorkProcessScheduleInfoService workProcessScheduleInfoService;
    private CaseApproveRecordService caseApproveRecordService;
    private WorkTaskPoolService workTaskPoolService;
    private WorkTaskPoolHistoryService workTaskPoolHistoryService;
    private ApproveInformInfoService approveInformInfoService;
    private UserCollocationService userCollocationService;
    private CaseTortoiseApplyService caseTortoiseApplyService;
    private CaseTortoiseService caseTortoiseService;
    private CaseConfParamService caseConfParamService;
    private CaseCustAddressService  caseCustAddressService;
    private CaseCustInfoService caseCustInfoService;
    private CaseCustContactService caseCustContactService;
    private CaseCustIndividualService  caseCustIndividualServicex;
    private ChannelBaseInfoService channelBaseInfoService;
    private ChannelRiskInfoService channelRiskInfoService;
    private WorkProcessScheduleInfoTempService workProcessScheduleInfoTempService;
    private CaseRedundantInfoService redundantInfoService ;

    private OpraHolidayService opraHolidayService;
    private BaseHolidayService baseHolidayService;


    /**
     * @Description 流程发起
     * @Author Peng_Jinbo
     * @Date 2020/7/17 18:06
     */
    @Override
    public WorkFlowResponse start(WorkProcessScheduleInfoTemp temp) {
        StartFlowRequest request = new StartFlowRequest();
        request.setAfsFlowKey(temp.getAfsFlowKey());
        request.setBizDataId(Convert.toStr(temp.getId()));
        request.setFlowName(new StringBuffer(temp.getApplyNo())
                .append("-")
                .append(WorkflowTypeUtil.getApproveTypeName(temp.getAfsFlowKey()))
                .append("(")
                .append(WorkflowTypeUtil.getType(temp.getAfsFlowKey()).getDesc())
                .append(")").toString());
        log.info("流程发起 ==> {}", request);
        WorkFlowResponse response = workflowService.startWorkFlow(request, getBusinessData(temp.getApplyNo()));
        if (Const.WORKFLOW_RESPONSE_SUCCESS == response.getSuccess()) {
            saveStartRecord(temp, caseBaseInfoService.getOne(Wrappers.<CaseBaseInfo>lambdaQuery().eq(CaseBaseInfo::getApplyNo, temp.getApplyNo())));
        } else {
            // 失败时删除临时数据
            workProcessScheduleInfoTempService.removeWithNewTransactional(temp);
            throw new AfsBaseException(response.getCode(), response.getMessage());
        }
        return response;
    }

    /**
     * @Description 流程提交
     * @Author Peng_Jinbo
     * @Date 2020/7/17 18:05
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void submit(NormalTaskSubmitVO submitVO) {
        if (Objects.isNull(submitVO.getWorkFlowInfo())) {
            submitVO.setWorkFlowInfo(workProcessScheduleInfoService.getById(submitVO.getRecord().getStageId()));
        }
        if (Objects.isNull(submitVO.getWorkTaskPool())) {
            submitVO.setWorkTaskPool(workTaskPoolService.getOne(
                    Wrappers.<WorkTaskPool>lambdaQuery()
                            .eq(WorkTaskPool::getStageId, submitVO.getRecord().getStageId())
                            .eq(WorkTaskPool::getTaskNodeId, submitVO.getWorkFlowInfo().getCurrentNodeId())
                            .eq(WorkTaskPool::getApproveStaff, SecurityUtils.getUser().getUsername())
            ));
        }
        NormalSubmitType submitEnum = (NormalSubmitType) AfsEnumUtil.getEnum(submitVO.getRecord().getApproveSuggest(), NormalSubmitType.class);
        Assert.notNull(submitEnum,"未知的提交命令：" + submitVO.getRecord().getApproveSuggest());
        switch (submitEnum) {
            case SUGGEST_CHECK:
                check(submitVO);
                checkFlowTypeWhenFirstNodeSubmit(submitVO);
                break;
            case SUGGEST_CONDITION:
                condition(submitVO);
                checkFlowTypeWhenFirstNodeSubmit(submitVO);
                break;
            case SUGGEST_REJECT:
                reject(submitVO);
                checkFlowTypeWhenFirstNodeSubmit(submitVO);
                break;
            case SUGGEST_VISIT:
                visit(submitVO);
                break;
            case SUGGEST_CANCEL:
                checkCaseLock(submitVO);
                cancel(submitVO);
                tortoiseFraudWhenFlowEnd(submitVO);
                break;
            case SUGGEST_REJECT_FINAL:
                checkCaseLock(submitVO);
                checkApproveAmountLimit(submitVO);
                rejectFinal(submitVO);
                tortoiseFraudWhenFlowEnd(submitVO);
                break;
            case SUGGEST_CHECK_FINAL:
                checkCaseLock(submitVO);
                checkApproveAmountLimit(submitVO);
                checkFinal(submitVO);
                tortoiseFraudWhenFlowEnd(submitVO);
                break;
            case SUGGEST_CONDITION_FINAL:
                checkCaseLock(submitVO);
                checkApproveAmountLimit(submitVO);
                conditionFinal(submitVO);
                tortoiseFraudWhenFlowEnd(submitVO);
                break;
            case SEND_BACK:
                sendBack(submitVO);
                break;
            case SEND_BACK_TO_DEALER:
                //add by yk.Li 20200625
                sendBackToDealer(submitVO);
                break;
            case PARSE:
                parse(submitVO);
                break;
            case MODIFY_SUBMIT:
                dealerSubmit(submitVO);
                break;
            default:
                log.info("审批建议不存在:{}", submitEnum);
        }
    }

    /**
     * @Description 改派
     * @Author Peng_Jinbo
     * @Date 2020/7/17 18:05
     */
    @Override
    @Transactional
    public WorkFlowResponse reformist(NormalReformistVO reformistVO) {
        WorkProcessScheduleInfo info = workProcessScheduleInfoService.getById(reformistVO.getStageId());
        afterTaskHandlerChange(info, reformistVO);
        TaskReformistRequest reformistRequest = new TaskReformistRequest();
        reformistRequest.setAfsFlowKey(info.getAfsFlowKey());
        reformistRequest.setBizDataId(Convert.toStr(info.getId()));
        reformistRequest.setFlowInstanceId(info.getStageId());
        reformistRequest.setUserName(reformistVO.getReformistUserName());
        reformistRequest.setUserRealName(reformistVO.getReformistUserRealName());
        WorkFlowResponse response = workflowService.taskReformist(reformistRequest, getBusinessData(info.getApplyNo()));
        if (Const.WORKFLOW_RESPONSE_SUCCESS == response.getSuccess()) {
            return response;
        } else {
            throw new AfsBaseException(response.getCode(), response.getMessage());
        }
    }

    @Override
    @Transactional
    public WorkFlowResponse cancelFlow(String stageId, String message,boolean noticeToApplySys) {
        log.info("流程撤销 ==> 操作人：{},流程编号：{}", SecurityUtils.getUsernameWithDefault("system"), stageId);
        WorkProcessScheduleInfo info = workProcessScheduleInfoService.getById(stageId);
        // 撤销校验流程是否锁定
        checkCaseLock(NormalTaskSubmitVO.builder().workFlowInfo(info).build());
        List<WorkTaskPool> poolList = workTaskPoolService.list(
                Wrappers.<WorkTaskPool>lambdaQuery().eq(WorkTaskPool::getStageId, stageId)
        );
        CaseApproveRecord record = new CaseApproveRecord();
        record.setStageId(Convert.toStr(info.getId()));
        record.setUseScene(UseSceneEnum.APPROVE.getValue());
        record.setDisposeStaff(SecurityUtils.getUser()==null?"系统":SecurityUtils.getUser().getUserRealName());
        record.setApproveType(ApproveTypeEnum.PROCESS.getValue());
        record.setDisposeNode(info.getCurrentNodeId());
        record.setDisposeNodeName(info.getCurrentNodeName());
        // 任务处于分配中时没有任务，此时撤销不需要关注任务数据
        record.setApproveStartTime(CollectionUtil.isNotEmpty(poolList) ? poolList.get(0).getStartTime() : new Date());
        record.setApproveEndTime(new Date());
        record.setApproveSuggest(AfsEnumUtil.key(NormalSubmitType.SUGGEST_CANCEL));
        record.setApproveSuggestName(AfsEnumUtil.desc(NormalSubmitType.SUGGEST_CANCEL));
        record.setApplyNo(info.getApplyNo());
        record.setApproveRemark(message);

        if(CollectionUtil.isNotEmpty(poolList)){
            WorkTaskPool pool = poolList.get(0);
            String[] ignoreFieldNames = new String[]{"id", "createBy", "createTime", "delFlag"};
            WorkTaskPoolHistory history = new WorkTaskPoolHistory();
            BeanUtil.copyProperties(pool,history,ignoreFieldNames);
            history.setApproveStaff(Objects.isNull(SecurityUtils.getUser()) ? "system" :SecurityUtils.getUser().getUsername());
            history.setApproveStaffName(Objects.isNull(SecurityUtils.getUser()) ? "系统" :SecurityUtils.getUser().getUserRealName());
            history.setApproveSuggest(AfsEnumUtil.key(NormalSubmitType.SUGGEST_CANCEL));
            JSONObject remain = new JSONObject();
            remain.put(AfsEnumUtil.key(RemainKeyEnum.RECORD), JSON.toJSONString(record));
            history.setRemainData(remain.toJSONString());
            workTaskPoolHistoryService.save(history);
        }

        // 保存操作日志
        caseApproveRecordService.save(record);
        // 删除已存在的待办任务
        workTaskPoolService.removeByIds(poolList.stream().map(pool -> Convert.toStr(pool.getId())).collect(Collectors.toList()));

        // 更新案件状态
        caseBaseInfoService.update(
                Wrappers.<CaseBaseInfo>lambdaUpdate()
                        .eq(CaseBaseInfo::getApplyNo, record.getApplyNo())
                        .set(CaseBaseInfo::getBusinessStateIn, AfsEnumUtil.key(BusinessStateInEnum.REPEAL))
        );

        updateCaseStatusWhenEnd(NormalTaskSubmitVO.builder().workFlowInfo(info).record(record).build());

        // 调用工作流引擎接口
        FLowGiveUpRequest giveUpRequest = new FLowGiveUpRequest();
        giveUpRequest.setReason(message);
        giveUpRequest.setFlowInstanceId(info.getStageId());
        WorkFlowResponse response = workflowService.flowGiveUp(giveUpRequest);
        if (Const.WORKFLOW_RESPONSE_SUCCESS != response.getSuccess()) {
            throw new AfsBaseException(response.getCode(), response.getMessage());
        }
        if(noticeToApplySys) {
            // 通知进件系统
            callApplySystem(record);
            tortoiseFraudWhenFlowEnd(NormalTaskSubmitVO.builder().workFlowInfo(info).build());
        }
        return response;
    }

    @Override
    @Transactional
    public WorkFlowResponse callBackFlow(String scheduleId, String message,String callbackUsername,String callBackUserRealName) {
        WorkProcessScheduleInfo workProcessScheduleInfo = workProcessScheduleInfoService.getById(scheduleId);
        //获取撤回申请人最近一次的任务
        WorkTaskPoolHistory lastTimeWorkTask = workTaskPoolHistoryService.list(Wrappers.<WorkTaskPoolHistory>query().lambda()
                .eq(WorkTaskPoolHistory::getApplyNo,workProcessScheduleInfo.getApplyNo())
                .eq(WorkTaskPoolHistory::getProcessType, ProcessTypeEnum.GENERA_APPROVE.getCode())
                .eq(WorkTaskPoolHistory::getStageId,workProcessScheduleInfo.getId().toString())
                .eq(WorkTaskPoolHistory::getApproveStaff,callbackUsername)
                .orderByDesc(WorkTaskPoolHistory::getCreateTime)).get(0);
        //保存审批撤回操作日志
        CaseApproveRecord record = new CaseApproveRecord();
        record.setStageId(workProcessScheduleInfo.getStageId());
        record.setApplyNo(workProcessScheduleInfo.getApplyNo());
        record.setApproveStartTime(new Date());
        record.setApproveEndTime(record.getApproveStartTime());
        record.setApproveSuggest(AfsEnumUtil.key(NormalSubmitType.CALL_BACK));
        record.setApproveSuggestName(AfsEnumUtil.desc(NormalSubmitType.CALL_BACK));
        record.setDisposeNodeName(lastTimeWorkTask.getTaskNodeName());
        record.setDisposeNode(lastTimeWorkTask.getTaskNodeId());
        record.setDisposeStaff(callBackUserRealName);
        record.setApproveType(ApproveTypeEnum.PROCESS.getValue());
        record.setUseScene(UseSceneEnum.APPROVE.getValue());
        StringBuffer approveRemark = new StringBuffer("【").append(callBackUserRealName)
                .append("主动撤回案件】");
        record.setApproveRemark(approveRemark.toString());
        caseApproveRecordService.save(record);
        TaskCallBackRequest callBackRequest = new TaskCallBackRequest();
        callBackRequest.setAfsFlowKey(workProcessScheduleInfo.getAfsFlowKey());
        callBackRequest.setBizDataId(Convert.toStr(workProcessScheduleInfo.getId()));
        callBackRequest.setFlowInstanceId(workProcessScheduleInfo.getStageId());
        callBackRequest.setUserName(callbackUsername);
        callBackRequest.setUserRealName(callBackUserRealName);
        WorkFlowResponse response = workflowService.taskCallBack(callBackRequest, getBusinessData(workProcessScheduleInfo.getApplyNo()));
        if (Const.WORKFLOW_RESPONSE_SUCCESS == response.getSuccess()) {
            callBackTaskHandle(workProcessScheduleInfo,lastTimeWorkTask,record);
            return response;
        } else {
            throw new AfsBaseException(response.getCode(), response.getMessage());
        }
    }

    @Override
    public WorkFlowResponse cancelFlow(String stageId, String message) {
        return cancelFlow(stageId,message,true);
    }

    /**
     * @Description 保存流程发起日志
     * @Author Peng_Jinbo
     * @Date 2020/7/2 15:25
     */
    @Transactional(rollbackFor = Exception.class)
    public void saveStartRecord(WorkProcessScheduleInfoTemp infoTemp, CaseBaseInfo caseInfo) {
        CaseApproveRecord record = new CaseApproveRecord();
        record.setStageId(Convert.toStr(infoTemp.getId()));
        record.setApplyNo(infoTemp.getApplyNo());
        record.setApproveSuggestName("发起流程");
        record.setApproveType(ApproveTypeEnum.PROCESS.getValue());
        record.setApproveStartTime(new Date());
        record.setApproveEndTime(new Date());
        record.setDisposeStaff(Objects.isNull(SecurityUtils.getUser()) ? "系统" : SecurityUtils.getUser().getUserRealName());
        caseApproveRecordService.save(record);

        // 更改案件状态
        caseInfo.setBusinessStateIn(AfsEnumUtil.key(BusinessStateInEnum.TASK_ASSIGNING));
        caseInfo.setProcessorStartTime(new Date());
        caseInfo.setNormalApproveFlowId(infoTemp.getId().toString());
        caseInfo.setFlowRecycleStatus(WhetherEnum.NO.getCode());
        caseBaseInfoService.updateById(caseInfo);

        // 通知进件端
        CaseApproveRecord noticeRecord = new CaseApproveRecord();
        noticeRecord.setApplyNo(record.getApplyNo());
        noticeRecord.setApproveStartTime(new Date());
        noticeRecord.setApproveSuggest(SendApproveTypeEnum.PENDING_REVIEW.getCode());
        approveInformInfoService.submitApprovalNotic(noticeRecord);
    }

    /**
     * @Description 任务改派后删除当前任务数据
     * @Author Peng_Jinbo
     * @Date 2020/7/9 18:28
     */
    @Transactional(rollbackFor = Exception.class)
    public void afterTaskHandlerChange(WorkProcessScheduleInfo info, NormalReformistVO reformistVO) {
        WorkTaskPool pool = workTaskPoolService.getOne(Wrappers.<WorkTaskPool>lambdaQuery()
                .eq(WorkTaskPool::getStageId, info.getId().toString())
                .eq(WorkTaskPool::getApproveStaff, reformistVO.getOriUserName()));
        workTaskPoolService.removeById(pool.getId());

        // 保存操作日志
        CaseApproveRecord record = new CaseApproveRecord();
        record.setStageId(info.getStageId());
        record.setApplyNo(info.getApplyNo());
        record.setApproveStartTime(new Date());
        record.setApproveEndTime(record.getApproveStartTime());
        record.setApproveSuggest(AfsEnumUtil.key(NormalSubmitType.REFORMIST));
        record.setApproveSuggestName(AfsEnumUtil.desc(NormalSubmitType.REFORMIST));
        record.setDisposeNodeName(info.getCurrentNodeName());
        record.setDisposeNode(info.getCurrentNodeId());
        record.setDisposeStaff(SecurityUtils.getUser().getUserRealName());
        record.setApproveType(ApproveTypeEnum.PROCESS.getValue());
        record.setUseScene(UseSceneEnum.APPROVE.getValue());
        StringBuffer approveRemark = new StringBuffer("改派至").append(reformistVO.getReformistUserRealName()).append(" ");
        if (StrUtil.isNotBlank(pool.getRemainData())) {
            JSONObject json = JSONObject.parseObject(pool.getRemainData());
            if (json.containsKey(AfsEnumUtil.key(RemainKeyEnum.RECORD))) {
                CaseApproveRecord remindRecord = json.getObject(AfsEnumUtil.key(RemainKeyEnum.RECORD), CaseApproveRecord.class);
                if (StrUtil.isNotBlank(remindRecord.getApproveSuggest())) {
                    Map<String, List<DicDataDto>> suggestDicMap = DicHelper.getDicMaps("approveSuggest");
                    approveRemark.append(DicUtils.translate(remindRecord.getApproveSuggest(), suggestDicMap));
                    if (StrUtil.isNotBlank(remindRecord.getApproveReason())) {
                        String[] reasons = remindRecord.getApproveReason()
                                .replace("[", "")
                                .replace("]", "")
                                .split(",");
                        Map<String, List<DicDataDto>> reasonDicMap = DicHelper.getDicMaps(remindRecord.getApproveSuggest());
                        for (String reason : reasons) {
                            approveRemark.append("【")
                                    .append(DicUtils.translate(reason, reasonDicMap))
                                    .append("】,");
                        }
                    }
                }
                if (StrUtil.isNotBlank(remindRecord.getApproveRemark())) {
                    approveRemark.append(remindRecord.getApproveRemark());
                }
            }
        }
        record.setApproveRemark(approveRemark.toString());
        caseApproveRecordService.save(record);
        String[] ignoreFieldNames = new String[]{"id", "createBy", "createTime", "delFlag"};
        WorkTaskPoolHistory history = new WorkTaskPoolHistory();
        BeanUtil.copyProperties(pool, history, ignoreFieldNames);
        JSONObject remainData = StrUtil.isNotBlank(history.getRemainData()) ? JSONObject.parseObject(history.getRemainData()) : new JSONObject();
        if(remainData.containsKey(AfsEnumUtil.key(RemainKeyEnum.RECORD))){
            remainData.put(AfsEnumUtil.key(RemainKeyEnum.BEFORE_REFORMIST_RECORD),remainData.get(AfsEnumUtil.key(RemainKeyEnum.RECORD)));
        }
        remainData.put(AfsEnumUtil.key(RemainKeyEnum.RECORD), record);
        history.setRemainData(remainData.toJSONString());
        history.setEndTime(record.getApproveEndTime());
        history.setApproveSuggest(record.getApproveSuggest());
        history.setApproveStaff(SecurityUtils.getUser().getUsername());
        history.setApproveStaffName(SecurityUtils.getUser().getUserRealName());
        workTaskPoolHistoryService.save(history);
    }


    /**
     * 审批员撤回案件，更新任务信息
     * */
    @Transactional(rollbackFor = Exception.class)
    public void callBackTaskHandle(WorkProcessScheduleInfo workProcessScheduleInfo,WorkTaskPoolHistory lastTimeWorkTask,CaseApproveRecord record){
        //删除当前节点的待办任务
        WorkTaskPool pool = workTaskPoolService.getOne(Wrappers.<WorkTaskPool>lambdaQuery()
                .eq(WorkTaskPool::getStageId, workProcessScheduleInfo.getId().toString())
                .eq(WorkTaskPool::getTaskNodeId, workProcessScheduleInfo.getCurrentNodeId()));
        workTaskPoolService.removeById(pool.getId());
        //修改案件状态为：撤回
        caseBaseInfoService.update(
                Wrappers.<CaseBaseInfo>lambdaUpdate()
                        .eq(CaseBaseInfo::getApplyNo,workProcessScheduleInfo.getApplyNo())
                        .set(CaseBaseInfo::getBusinessStateIn, AfsEnumUtil.key(BusinessStateInEnum.REVOCATION)));
        //保存任务历史记录
        String[] ignoreHisFieldNames = new String[]{"id", "createBy", "createTime", "delFlag"};
        WorkTaskPoolHistory history = new WorkTaskPoolHistory();
        BeanUtil.copyProperties(lastTimeWorkTask, history, ignoreHisFieldNames);
        JSONObject remainData = StrUtil.isNotBlank(history.getRemainData()) ? JSONObject.parseObject(history.getRemainData()) : new JSONObject();
        remainData.put(AfsEnumUtil.key(RemainKeyEnum.RECORD), record);
        history.setRemainData(remainData.toJSONString());
        history.setCreateTime(record.getCreateTime());
        history.setEndTime(new Date());
        history.setApproveSuggest(record.getApproveSuggest());
        workTaskPoolHistoryService.save(history);
    }

    /**
     * @Description 经销商提交
     * @Author Peng_Jinbo
     * @Date 2020/7/8 18:02
     */
    private void dealerSubmit(NormalTaskSubmitVO submitVO) {
        caseBaseInfoService.update(
                Wrappers.<CaseBaseInfo>lambdaUpdate()
                        .eq(CaseBaseInfo::getApplyNo, submitVO.getWorkFlowInfo().getApplyNo())
                        .set(CaseBaseInfo::getBusinessStateIn, AfsEnumUtil.key(BusinessStateInEnum.REVISE_REPLY))
        );
        workTaskPoolService.removeById(submitVO.getWorkTaskPool().getId());
/*        String[] ignoreFieldNames = new String[]{"id", "createBy", "createTime", "delFlag"};
        WorkTaskPoolHistory history = new WorkTaskPoolHistory();
        BeanUtil.copyProperties(submitVO.getWorkTaskPool(),history,ignoreFieldNames);
        workTaskPoolHistoryService.save(history);*/
        caseApproveRecordService.save(submitVO.getRecord());
        WorkFlowResponse resp = pushWorkflow(NormalSubmitType.MODIFY_SUBMIT, submitVO);
        if (Const.WORKFLOW_RESPONSE_SUCCESS != resp.getSuccess()) {
            throw new AfsBaseException(resp.getCode(), resp.getMessage());
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public void parse(NormalTaskSubmitVO submitVO) {
        // 更改案件状态
        CaseApproveRecord record = submitVO.getRecord();
        CaseBaseInfo baseInfo = caseBaseInfoService.getOne(
                Wrappers.<CaseBaseInfo>lambdaQuery()
                    .eq(CaseBaseInfo::getApplyNo,record.getApplyNo())
        );
        if(StrUtil.equals(baseInfo.getBusinessStateIn(),AfsEnumUtil.key(BusinessStateInEnum.PAUSE))){
            throw new AfsBaseException("操作失败：当前案件已处于暂停状态");
        }
        baseInfo.setBusinessStateIn(AfsEnumUtil.key(BusinessStateInEnum.PAUSE));
        caseBaseInfoService.updateById(baseInfo);

        caseApproveRecordService.save(record);
        WorkFlowResponse response = workflowService.pauseFlowInstance(submitVO.getWorkFlowInfo().getStageId());
        if(Const.WORKFLOW_RESPONSE_SUCCESS != response.getSuccess()){
            throw new AfsBaseException("操作失败："+ response.getMessage());
        }
    }

    /**
     * @Description 建议核准
     * @Author Peng_Jinbo
     * @Date 2020/6/16 13:53
     */
    public void check(NormalTaskSubmitVO submitVO) {
        changeCaseStatusAndSaveRecord(BusinessStateInEnum.ADVICE_APPROVED, submitVO);
        WorkFlowResponse resp = pushWorkflow(NormalSubmitType.SUGGEST_CHECK, submitVO);
        afterSubmit(resp);
    }

    /**
     * @Description 建议附条件核准
     * @Author Peng_Jinbo
     * @Date 2020/6/16 13:53
     */
    public void condition(NormalTaskSubmitVO submitVO) {
        changeCaseStatusAndSaveRecord(BusinessStateInEnum.ADVICE_CONDITIONAL, submitVO);
        WorkFlowResponse resp = pushWorkflow(NormalSubmitType.SUGGEST_CONDITION, submitVO);
        afterSubmit(resp);
    }

    /**
     * @Description 建议拒绝
     * @Author Peng_Jinbo
     * @Date 2020/6/16 13:53
     */
    public void reject(NormalTaskSubmitVO submitVO) {
        changeCaseStatusAndSaveRecord(BusinessStateInEnum.ADVICE_REJECT, submitVO);
        WorkFlowResponse resp = pushWorkflow(NormalSubmitType.SUGGEST_REJECT, submitVO);
        afterSubmit(resp);
    }

    /**
     * @Description 建议家访
     * @Author Peng_Jinbo
     * @Date 2020/6/16 13:53
     */
    public void visit(NormalTaskSubmitVO submitVO) {
        changeCaseStatusAndSaveRecord(BusinessStateInEnum.VISIT, submitVO);
        WorkFlowResponse resp = pushWorkflow(NormalSubmitType.SUGGEST_VISIT, submitVO);
        afterSubmit(resp);
        // TODO 初始化家访数据
    }

    /**
     * @Description 撤销
     * @Author Peng_Jinbo
     * @Date 2020/6/16 13:53
     */
    public void cancel(NormalTaskSubmitVO submitVO) {
        changeCaseStatusAndSaveRecord(BusinessStateInEnum.REPEAL, submitVO);

        // 撤销提交
        FLowGiveUpRequest giveUpRequest = new FLowGiveUpRequest();
        giveUpRequest.setFlowInstanceId(submitVO.getWorkFlowInfo().getStageId());
        giveUpRequest.setReason(submitVO.getRecord().getApproveRemark());
        workflowService.flowGiveUp(giveUpRequest);
        callApplySystem(submitVO.getRecord());
    }

    /**
     * @Description 拒绝
     * @Author Peng_Jinbo
     * @Date 2020/6/16 13:54
     */
    public void rejectFinal(NormalTaskSubmitVO submitVO) {
        changeCaseStatusAndSaveRecord(BusinessStateInEnum.REJECT, submitVO);
        WorkFlowResponse resp = pushWorkflow(NormalSubmitType.SUGGEST_REJECT_FINAL, submitVO);
        afterSubmit(resp);
        callApplySystem(submitVO.getRecord());
    }

    /**
     * @Description 核准
     * @Author Peng_Jinbo
     * @Date 2020/6/16 13:54
     */
    public void checkFinal(NormalTaskSubmitVO submitVO) {
        changeCaseStatusAndSaveRecord(BusinessStateInEnum.APPROVED, submitVO);
        WorkFlowResponse resp = pushWorkflow(NormalSubmitType.SUGGEST_CHECK_FINAL, submitVO);
        afterSubmit(resp);
        callApplySystem(submitVO.getRecord());
    }

    /**
     * @Description 附条件核准
     * @Author Peng_Jinbo
     * @Date 2020/6/16 13:54
     */
    public void conditionFinal(NormalTaskSubmitVO submitVO) {
        changeCaseStatusAndSaveRecord(BusinessStateInEnum.CONDITIONAL_APPROVE, submitVO);
        WorkFlowResponse resp = pushWorkflow(NormalSubmitType.SUGGEST_CONDITION_FINAL, submitVO);
        afterSubmit(resp);
        approveInformInfoService.submitConditionalApproval(submitVO.getRecord());
    }

    /**
     * @Description 退回
     * @Author Peng_Jinbo
     * @Date 2020/6/16 13:54
     */
    public void sendBack(NormalTaskSubmitVO submitVO) {
        if (WhetherEnum.YES.getCode().equals(submitVO.getWorkFlowInfo().getFirstTrail())) {
            checkCaseLock(submitVO);
            sendBackToDealer(submitVO);
        } else {
            changeCaseStatusAndSaveRecord(BusinessStateInEnum.NONE, submitVO);
            WorkFlowResponse resp = pushWorkflow(NormalSubmitType.SEND_BACK, submitVO);
            afterSubmit(resp);
        }
    }

    /**
     * @Description 退回至经销商
     * @Author Peng_Jinbo
     * @Date 2020/6/19 11:48
     */
    public void sendBackToDealer(NormalTaskSubmitVO submitVO) {
        submitVO.getRecord().setApproveSuggest(AfsEnumUtil.key(NormalSubmitType.SEND_BACK_TO_DEALER));
        submitVO.getRecord().setApproveSuggestName(AfsEnumUtil.desc(NormalSubmitType.SEND_BACK_TO_DEALER));
        if(Objects.nonNull(submitVO.getNoticeClientRecord())){
            submitVO.getNoticeClientRecord().setApproveSuggest(submitVO.getRecord().getApproveSuggest());
            submitVO.getNoticeClientRecord().setApproveSuggestName(submitVO.getRecord().getApproveSuggestName());
        }
        /**add by gjq 1011 附条件核准时不允许退回经销商*/
        this.checkCondition(submitVO.getRecord());

        changeCaseStatusAndSaveRecord(BusinessStateInEnum.REVISE_PARSE, submitVO);
        WorkFlowResponse resp = pushWorkflow(NormalSubmitType.SEND_BACK_TO_DEALER, submitVO);
        afterSubmit(resp);
        approveInformInfoService.submitApprovalNotic(Objects.nonNull(submitVO.getNoticeClientRecord())? submitVO.getNoticeClientRecord() : submitVO.getRecord());
        /**推送数据到进件端*/
        sendInfoToApply(submitVO.getRecord().getApplyNo(),AfsEnumUtil.key(NormalSubmitType.SEND_BACK_TO_DEALER));
    }

    /**
     * @Description 经销商主动撤回
     * @Author ma_xueyu
     * @Date 2020-08-31
     */
    public WorkFlowResponse dealerCallBackFlow(NormalTaskSubmitVO submitVO){
        // 更改案件状态：草稿
        CaseApproveRecord record = submitVO.getRecord();
        caseBaseInfoService.update(
                Wrappers.<CaseBaseInfo>lambdaUpdate()
                        .eq(CaseBaseInfo::getApplyNo, record.getApplyNo())
                        .set(CaseBaseInfo::getBusinessStateIn, AfsEnumUtil.key(BusinessStateInEnum.DRAFT))
        );
        //删除历史任务记录
        workTaskPoolHistoryService.remove(Wrappers.<WorkTaskPoolHistory>lambdaQuery()
                .eq(WorkTaskPoolHistory::getStageId, submitVO.getWorkFlowInfo().getId())
                .eq(WorkTaskPoolHistory::getApplyNo, submitVO.getWorkFlowInfo().getApplyNo()));
        // 删除当前任务，存入历史任务表
        WorkTaskPool taskPool = submitVO.getWorkTaskPool();
        List<WorkTaskPool> currentNodeTask = workTaskPoolService.list(
                Wrappers.<WorkTaskPool>lambdaQuery().eq(WorkTaskPool::getStageId, taskPool.getStageId())
                        .eq(WorkTaskPool::getTaskNodeId, taskPool.getTaskNodeId())
        );
        taskPool.setApproveSuggest(AfsEnumUtil.key(CallBackTypeEnum.WORKFLOW_APPLY));
        record.setDisposeNode(taskPool.getTaskNodeId());
        record.setDisposeNodeName(taskPool.getTaskNodeName());
        WorkTaskPoolHistory currentPoolHistory = new WorkTaskPoolHistory();
        String[] ignoreFieldNames = new String[]{"id", "createBy", "createTime", "delFlag"};
        BeanUtil.copyProperties(taskPool, currentPoolHistory, ignoreFieldNames);
        List<Long> ids = new ArrayList<>(currentNodeTask.size());
        currentNodeTask.forEach(task -> ids.add(task.getId()));
        workTaskPoolService.removeByIds(ids);
        workTaskPoolHistoryService.save(currentPoolHistory);
        // 保存流程操作日志
        caseApproveRecordService.save(record);
        // 调用工作流引擎接口废弃当前流程
        FLowGiveUpRequest giveUpRequest = new FLowGiveUpRequest();
        giveUpRequest.setReason(AfsEnumUtil.desc(CallBackTypeEnum.WORKFLOW_APPLY));
        giveUpRequest.setFlowInstanceId(submitVO.getWorkFlowInfo().getStageId());
        WorkFlowResponse response = workflowService.flowGiveUp(giveUpRequest);
        if (Const.WORKFLOW_RESPONSE_SUCCESS != response.getSuccess()) {
            throw new AfsBaseException(response.getCode(), response.getMessage());
        }
        return response;
    }


    /**
     * @Description 通知进件系统（常规审批通知）
     * @Author Peng_Jinbo
     * @Date 2020/6/16 19:13
     */
    public void callApplySystem(CaseApproveRecord record) {
        approveInformInfoService.submitApprovalNotic(record);
    }

    /**
     * @Description 更改案件状态，保存日志
     * @Author Peng_Jinbo
     * @Date 2020/6/16 17:42
     */
    @Transactional(rollbackFor = Exception.class)
    public void changeCaseStatusAndSaveRecord(BusinessStateInEnum stateInEnum, NormalTaskSubmitVO submitVO) {
        // 更改案件状态
        CaseApproveRecord record = submitVO.getRecord();
        if (!stateInEnum.equals(BusinessStateInEnum.NONE)) {
            caseBaseInfoService.update(
                    Wrappers.<CaseBaseInfo>lambdaUpdate()
                            .eq(CaseBaseInfo::getApplyNo, record.getApplyNo())
                            .set(CaseBaseInfo::getBusinessStateIn, AfsEnumUtil.key(stateInEnum))
            );
        }
        AfsUser user = SecurityUtils.getUser();
        // 删除当前任务，存入历史任务表
        WorkTaskPool taskPool = submitVO.getWorkTaskPool();
        List<WorkTaskPool> currentNodeTask = workTaskPoolService.list(
                Wrappers.<WorkTaskPool>lambdaQuery().eq(WorkTaskPool::getStageId, taskPool.getStageId())
                        .eq(WorkTaskPool::getTaskNodeId, taskPool.getTaskNodeId())
        );
        taskPool.setEndTime(new Date());
        taskPool.setApproveSuggest(record.getApproveSuggest());
        if(StrUtil.isNotBlank(record.getApproveSuggest()) && StrUtil.isBlank(record.getApproveSuggestName())){
            NormalSubmitType submitType = (NormalSubmitType) AfsEnumUtil.getEnum(record.getApproveSuggest(),NormalSubmitType.class);
            if(Objects.nonNull(submitType)){
                record.setApproveSuggestName(AfsEnumUtil.desc(submitType));
            }
        }
        record.setDisposeStaff(SecurityUtils.getUser().getUserRealName());
        record.setDisposeNode(taskPool.getTaskNodeId());
        record.setDisposeNodeName(taskPool.getTaskNodeName());
        record.setApproveStartTime(taskPool.getStartTime());
        record.setApproveEndTime(taskPool.getEndTime());
        // 保存审批建议数据，暂存
        JSONObject remain = new JSONObject();
        if (StrUtil.isNotBlank(taskPool.getRemainData())) {
            remain = JSONObject.parseObject(taskPool.getRemainData());
        }
        remain.put(AfsEnumUtil.key(RemainKeyEnum.RECORD), JSONObject.toJSON(record));
        taskPool.setRemainData(remain.toString());
        WorkTaskPoolHistory taskPoolHistory = workTaskPoolHistoryService.getOne(
                Wrappers.<WorkTaskPoolHistory>lambdaQuery()
                        .eq(WorkTaskPoolHistory::getStageId, record.getStageId())
                        .eq(WorkTaskPoolHistory::getTaskNodeId, submitVO.getWorkTaskPool().getTaskNodeId())
                        .ne(WorkTaskPoolHistory::getApproveSuggest,AfsEnumUtil.key(NormalSubmitType.REFORMIST))
                        .ne(WorkTaskPoolHistory::getApproveSuggest,AfsEnumUtil.key(NormalSubmitType.CALL_BACK))
        );
        if (Objects.nonNull(taskPoolHistory)) {
            workTaskPoolHistoryService.removeById(taskPoolHistory);
        }
        WorkTaskPoolHistory currentPoolHistory = new WorkTaskPoolHistory();
        String[] ignoreFieldNames = new String[]{"id", "createBy", "createTime", "delFlag"};
        BeanUtil.copyProperties(taskPool, currentPoolHistory, ignoreFieldNames);
        List<Long> ids = new ArrayList<>(currentNodeTask.size());
        currentNodeTask.forEach(task -> ids.add(task.getId()));
        workTaskPoolService.removeByIds(ids);
        workTaskPoolHistoryService.save(currentPoolHistory);

        // 保存流程操作日志
        caseApproveRecordService.save(record);
        submitVO.setHistory(currentPoolHistory);
        updateCaseStatusWhenEnd(submitVO);
    }

    /**
     * @Description 提交成功修改数据
     * @Author Peng_Jinbo
     * @Date 2020/7/2 18:59
     */
    public void afterSubmit(WorkFlowResponse resp) {
        if (Const.WORKFLOW_RESPONSE_SUCCESS != resp.getSuccess()) {
            throw new AfsBaseException(resp.getCode(), resp.getMessage());
        }
    }


    /**
     * @Description 流程结束时更改案件状态
     * @Author Peng_Jinbo
     * @Date 2020/7/20 10:11
     */
    public void updateCaseStatusWhenEnd(NormalTaskSubmitVO submitVO) {
        CaseApproveRecord caseApproveRecord = submitVO.getRecord();
        WorkProcessScheduleInfo info = submitVO.getWorkFlowInfo();
        // 流程结束处理 TODO 取消流程时也需要处理
        if (AfsEnumUtil.key(NormalSubmitType.SUGGEST_REJECT_FINAL).equals(caseApproveRecord.getApproveSuggest())
                || AfsEnumUtil.key(NormalSubmitType.SUGGEST_CONDITION_FINAL).equals(caseApproveRecord.getApproveSuggest())
                || AfsEnumUtil.key(NormalSubmitType.SUGGEST_CHECK_FINAL).equals(caseApproveRecord.getApproveSuggest())
                | AfsEnumUtil.key(NormalSubmitType.SUGGEST_CANCEL).equals(caseApproveRecord.getApproveSuggest())) {
            info.setEndTime(new Date());
            if(Objects.nonNull(submitVO.getHistory()) && StrUtil.equals(submitVO.getWorkFlowInfo().getUncertainNode(),WhetherEnum.YES.getCode())){
                submitVO.getHistory().setLastNode(WhetherEnum.YES.getCode());
                workTaskPoolHistoryService.saveOrUpdate(submitVO.getHistory());
            }
            CaseBaseInfo baseInfo = caseBaseInfoService.getOne(
                    Wrappers.<CaseBaseInfo>lambdaQuery()
                        .eq(CaseBaseInfo::getApplyNo,submitVO.getRecord().getApplyNo())
            );
            // 流程结束时间
            baseInfo.setProcessorEndTime(info.getEndTime());
            // 拒绝原因
            if(AfsEnumUtil.key(NormalSubmitType.SUGGEST_REJECT_FINAL).equals(caseApproveRecord.getApproveSuggest())){
                baseInfo.setRejectReason(caseApproveRecord.getApproveReason());
                baseInfo.setNormalApproveFlowId(Convert.toStr(info.getId()));
            }
            // 附条件核准
            if(AfsEnumUtil.key(NormalSubmitType.SUGGEST_CONDITION_FINAL).equals(caseApproveRecord.getApproveSuggest())){
                baseInfo.setRejectReason("");
                baseInfo.setNormalApproveFlowId(Convert.toStr(info.getId()));
                baseInfo.setConditionMark(WhetherEnum.YES.getCode());
                baseInfo.setPassLastDate(new Date());
                /**更新案件融资信息*/
                BigDecimal loanAmt=BigDecimal.ZERO;
                BigDecimal oldLoanAmtRepeat=baseInfo.getLoanAmtRepeat();
                List<FinCostDetails> finCostInfoArrayList=caseCostInfoService.list(Wrappers.<FinCostDetails>query().lambda()
                .eq(FinCostDetails::getApplyNo,submitVO.getRecord().getApplyNo()));
                if(!CollectionUtils.isEmpty(finCostInfoArrayList)){
                    for(FinCostDetails finCostDetails:finCostInfoArrayList){
                        loanAmt=loanAmt.add(finCostDetails.getLoanAmt());
                        if (CostTypeEnum.CARAMT.getCode().equals(finCostDetails.getCostType())) {
                            baseInfo.setDownPayScaleRepeat(finCostDetails.getDownPayScale());
                            baseInfo.setLoanTermsRepeat(finCostDetails.getLoanTerm());
                        }
                    }
                }
                baseInfo.setLoanAmtRepeat(loanAmt);
                /**重新计算累加贷额*/
                baseInfo.setTotalLoanAmt(baseInfo.getTotalLoanAmt().subtract(oldLoanAmtRepeat).add(loanAmt));
                /**推送数据到进件端*/
                sendInfoToApply(submitVO.getRecord().getApplyNo(),AfsEnumUtil.key(NormalSubmitType.SUGGEST_CONDITION_FINAL));
            }
            // 核准
            if(AfsEnumUtil.key(NormalSubmitType.SUGGEST_CHECK_FINAL).equals(caseApproveRecord.getApproveSuggest())){
                baseInfo.setNormalApproveFlowId(Convert.toStr(info.getId()));
                baseInfo.setPassLastDate(new Date());
                baseInfo.setRejectReason("");
                /**推送数据到进件端*/
                sendInfoToApply(submitVO.getRecord().getApplyNo(),AfsEnumUtil.key(NormalSubmitType.SUGGEST_CHECK_FINAL));
            }
            baseInfo.setFinalApproveResult(caseApproveRecord.getApproveSuggest());
            caseBaseInfoService.updateById(baseInfo);
        }
    }

    /**
     * @Description 提交，工作流推进
     * @Author Peng_Jinbo
     * @Date 2020/6/16 13:52
     */
    public WorkFlowResponse pushWorkflow(Enum<? extends AfsBaseEnum> submitButtonEnum, NormalTaskSubmitVO submitVO) {
        WorkTaskPool taskPool = submitVO.getWorkTaskPool();
        String cmdName = AfsEnumUtil.desc(submitButtonEnum);
        QueryFLowCmdRequest cmdQueryRequest = new QueryFLowCmdRequest();
        cmdQueryRequest.setFlowInstanceId(submitVO.getWorkFlowInfo().getStageId());
        WorkFlowResponse<List<FlowCmdBean>> flowCmdResp = workflowService.queryFlowCmd(cmdQueryRequest);
        Assert.isTrue(Const.WORKFLOW_RESPONSE_SUCCESS == flowCmdResp.getSuccess(), flowCmdResp.getMessage());
        Assert.isTrue(CollectionUtil.isNotEmpty(flowCmdResp.getAfsData()), "未获取到当前节点可操作命令");
        TaskSubmitRequest submitRequest = new TaskSubmitRequest();
        List<FlowCmdBean> cmdBeanList = flowCmdResp.getAfsData();
        for (FlowCmdBean flowCmdBean : cmdBeanList) {
            if (StrUtil.equals(flowCmdBean.getCmdDis(), cmdName)) {
                submitRequest.setAfsFlowKey(submitVO.getWorkFlowInfo().getAfsFlowKey());
                submitRequest.setCmdId(flowCmdBean.getId());
                submitRequest.setBizDataId(taskPool.getStageId());
                submitRequest.setGwtUserId(taskPool.getWorkflowDisposeId());
                break;
            }
        }
        Assert.isTrue(StrUtil.isNotBlank(submitRequest.getGwtUserId()), "当前节点未知的提交命令：" + cmdName);
        return workflowService.taskSubmit(submitRequest, getBusinessData(submitVO.getRecord().getApplyNo()));
    }


    /**
     * @Description 业务数据获取
     * @Author Peng_Jinbo
     * @Date 2020/7/17 18:24
     */
    public JSONObject getBusinessData(String applyNo) {
        // 基本信息
        CaseBaseInfo caseBaseInfo = caseBaseInfoService.getOne(
                Wrappers.<CaseBaseInfo>lambdaQuery().eq(CaseBaseInfo::getApplyNo, applyNo)
        );
        // 车款费用信息
        FinCostDetails finCostInfoCar = caseCostInfoService.list(
                Wrappers.<FinCostDetails>lambdaQuery().eq(FinCostDetails::getApplyNo, applyNo)
                        .eq(FinCostDetails::getCostType, CostTypeEnum.CARAMT.getCode())
        ).stream().findFirst().orElse(new FinCostDetails());

        // 附加贷费用信息
        FinCostDetails finCostInfoAppend = caseCostInfoService.list(
                Wrappers.<FinCostDetails>lambdaQuery().eq(FinCostDetails::getApplyNo, applyNo)
                        .eq(FinCostDetails::getCostType, CostTypeEnum.AFFIXAMT.getCode())
        ).stream().findFirst().orElse(new FinCostDetails());

        // 渠道信息
        CaseChannelInfo channelInfo = caseChannelInfoService.list(
                Wrappers.<CaseChannelInfo>lambdaQuery().eq(CaseChannelInfo::getApplyNo, applyNo)
        ).stream().findFirst().orElse(new CaseChannelInfo());
        ChannelRiskInfo channelRiskInfo = new ChannelRiskInfo();
        ChannelBaseInfo channelBaseInfo = new ChannelBaseInfo();
        if(StrUtil.isNotBlank(channelInfo.getDealerNo())){
            Optional<ChannelBaseInfo> channelBaseOpt = Optional.ofNullable(channelBaseInfoService.getOne(
                    Wrappers.<ChannelBaseInfo>lambdaQuery()
                        .eq(ChannelBaseInfo::getChannelCode,channelInfo.getDealerNo())
            ));
            if(channelBaseOpt.isPresent() && Objects.nonNull(channelBaseOpt.get().getChannelId())){
                channelBaseInfo = channelBaseOpt.get();
                Optional<ChannelRiskInfo> channelRiskInfoOpt = Optional.ofNullable(channelRiskInfoService.getOne(
                        Wrappers.<ChannelRiskInfo>lambdaQuery()
                            .eq(ChannelRiskInfo::getChannelId,channelBaseOpt.get().getChannelId())
                            .eq(ChannelRiskInfo::getBusinessType,caseBaseInfo.getBusinessType())
                ));
                if(channelRiskInfoOpt.isPresent()){
                    channelRiskInfo = channelRiskInfoOpt.get();
                }
            }
        }

        // 车辆信息
        CaseCarInfo caseCarInfo = caseCarInfoService.list(
                Wrappers.<CaseCarInfo>lambdaQuery().eq(CaseCarInfo::getApplyNo, applyNo)
        ).stream().findFirst().orElse(new CaseCarInfo());

        // 车辆详情信息
        CaseCarStyleDetail carStyleDetailInfo = caseCarStyleDetailService.list(
                Wrappers.<CaseCarStyleDetail>lambdaQuery().eq(CaseCarStyleDetail::getCarId, caseCarInfo.getId())
        ).stream().findFirst().orElse(new CaseCarStyleDetail());

        CaseTortoiseApply caseTortoiseApply = caseTortoiseApplyService.list(
                Wrappers.<CaseTortoiseApply>lambdaQuery()
                    .eq(CaseTortoiseApply::getApplyNo,applyNo)
                    .orderByDesc(CaseTortoiseApply::getOperateDate)
        ).stream().findFirst().orElse(new CaseTortoiseApply());

        NormalBusinessDataVO businessDataVO = NormalBusinessDataVO.builder()
                .loanAmountAddUp(caseBaseInfo.getTotalLoanAmt())
                .businessType(caseBaseInfo.getBusinessType())
                .decisionValue(caseTortoiseApply.getDecisionResult())//决策引擎返回值
                .XuanWuGrade(caseTortoiseApply.getScore())//玄武评分
                .dealerQualityGrade(channelRiskInfo.getQualityGrade())//经销商优质等级
                .turningMark("")
                .conditionMark(caseBaseInfo.getConditionMark())
                .assigned("")//是否指定处理人
                .carType(Convert.toStr(caseBaseInfo.getCarType()))
                .carNature(Convert.toStr(caseBaseInfo.getCarNature()))
                .operateWay(Convert.toStr(caseBaseInfo.getOperateWay(), ""))
                .affiliatedWay(caseBaseInfo.getAffiliatedWay())
                .qualityGrade("")//优质等级
                .newEnergy(carStyleDetailInfo.getIsGreen())
                .channelBelong(channelBaseInfo.getChannelBelong())//渠道归属
                .appendLoanAmount(finCostInfoAppend.getLoanAmt())
                .carLevel(caseCarInfo.getCarBodyClass())
                .assetsClass(carStyleDetailInfo.getCarType())
                .carTypeDetail(carStyleDetailInfo.getCarTypeDetail())
                .dealerName(channelInfo.getDealerName())
                .antiFraudGrade(caseTortoiseApply.getFraudResultScore())//反欺诈评分
                .decisionGrade(caseTortoiseApply.getScoreLevel())//决策引擎评级
                .loanAmount(finCostInfoCar.getLoanAmt())
                .carDownPayScale(finCostInfoCar.getDownPayScale())
                .carLoanAmount(finCostInfoCar.getLoanAmt())
                .carDiscountAmount(Convert.toBigDecimal(finCostInfoCar.getDiscountAmt()))
                .carFinalPayment(finCostInfoCar.getTailPayAmt())
                .carRepayType(finCostInfoCar.getAlgorithmType())
                .appendDownPayScale(finCostInfoAppend.getDownPayScale())
                .appendLoanAmount(finCostInfoAppend.getLoanAmt())
                .appendDiscountAmount(finCostInfoAppend.getDiscountAmt())
                .appendFinalPayment(finCostInfoAppend.getTailPayAmt())
                .remoteSign(caseBaseInfo.getAutomaticTag())
                .build();
        return JSONObject.parseObject(JSONObject.toJSONString(businessDataVO));
    }

    /**
    * @Description 检查案件锁定状态
    * @Author Peng_Jinbo
    * @Date 2020/9/4 18:18
    */
    private void checkCaseLock(NormalTaskSubmitVO submitVO){
        CaseBaseInfo baseInfo = caseBaseInfoService.getOne(Wrappers.<CaseBaseInfo>lambdaQuery().eq(CaseBaseInfo::getApplyNo, submitVO.getWorkFlowInfo().getApplyNo()));
        Assert.isTrue(!StrUtil.equals(WhetherEnum.YES.getCode(),baseInfo.getIsLock()),"操作失败，当前案件已处于锁定状态");
    }

    /**
     * @Description 校验当前操作员审批金额
     * @Author Peng_Jinbo
     * @Date 2020/7/23 17:31
     */
    private void checkApproveAmountLimit(NormalTaskSubmitVO submitVO) {
        CaseBaseInfo baseInfo = caseBaseInfoService.getOne(Wrappers.<CaseBaseInfo>lambdaQuery().eq(CaseBaseInfo::getApplyNo, submitVO.getWorkFlowInfo().getApplyNo()));
        UserCollocation user = userCollocationService.getOne(Wrappers.<UserCollocation>lambdaQuery().eq(UserCollocation::getLoginName, SecurityUtils.getUsername()));
        if (Convert.toBigDecimal(baseInfo.getTotalLoanAmt(),BigDecimal.ZERO).compareTo(Convert.toBigDecimal(user.getApprovedAmount(), BigDecimal.ZERO)) == 1) {
            throw new AfsBaseException("操作失败，当前操作员审批金额权限不够");
        }
    }

    /**
    * @Description 常规流程/正式复议流程结束时自动触发玄武反欺诈
    * @Author Peng_Jinbo
    * @Date 2020/9/2 19:18
    */
    private void tortoiseFraudWhenFlowEnd(NormalTaskSubmitVO submitVO){
        WorkflowTypeEnum flowType = WorkflowTypeUtil.getType(submitVO.getWorkFlowInfo().getAfsFlowKey()).getApproveType();
        if(flowType == ProcessTypeEnum.GENERA_APPROVE
            || flowType == ProcessTypeEnum.FORMAL_REVIEW) {
            // 延迟发送，玄武系统无法控制调用顺序此处为了当前场景调用在反欺诈数据推送场景推送成功之后触发
            GwtTortoiseAntiFraudCallStep callStep = GwtTortoiseAntiFraudCallStep.AFTER_FINALLY_APPROVE_END;
            GwtTortoiseStartApproveType approveType = GwtTortoiseStartApproveType.NORMAL;
            if(ProcessTypeEnum.FORMAL_REVIEW == flowType){ // 复议标识
                approveType = GwtTortoiseStartApproveType.REVIEW;
            }
            // 推送反欺诈数据
            if(caseConfParamService.checkSwitch(Const.PARAMS_SWITCH_XUANWU)){
                caseTortoiseService.signalFraudPush(submitVO.getWorkFlowInfo().getApplyNo(),approveType);
            }
            // 避免流程流转时事务未提交导致提供给玄武的数据为旧数据
            caseTortoiseService.safeDelaySignFraudHand(submitVO.getWorkFlowInfo().getApplyNo(), callStep, approveType);
        }
    }
    /**
     * @description: 推送数据到进件端
     * @author jiaqi.guo
     * @created 2020/9/18 22:39
     * @version 1.0
     */
    private void sendInfoToApply(String applyNo,String submitType){
        /**推送数据到进件端*/
        CaseCarInfo caseCarInfo = caseCarInfoService.getOne(Wrappers.<CaseCarInfo>lambdaQuery()
                .eq(CaseCarInfo::getApplyNo, applyNo));
        List <CaseUpdateDetailDto> detailDtoList=assemblyDataByApplyNo(applyNo);
        CaseUpdateInfoSend caseUpdateInfoSend= new CaseUpdateInfoSend();
        caseUpdateInfoSend.setApplyNo(applyNo);
        caseUpdateInfoSend.setApproveSuggest(submitType);
        caseUpdateInfoSend.setCaseUpdateDetailDtoList(detailDtoList);
        if (ObjectUtils.isNotEmpty(caseCarInfo)) {
            caseUpdateInfoSend.setLicenseProvince(caseCarInfo.getLicenseProvince());
            caseUpdateInfoSend.setLicenseCity(caseCarInfo.getLicenseCity());
        }
        approveInformInfoService.caseUpdateInfoSend(caseUpdateInfoSend);
    }
    /**
     * @description: 附条件核准/核准/退回 推送数据
     * @author jiaqi.guo
     * @created 2020/9/18 21:34
     * @version 1.0
     */
    private List<CaseUpdateDetailDto>  assemblyDataByApplyNo(String applyNo){
        List<String> list= new ArrayList<>();
        list.add(CustRoleEnum.MIANCUST.getCode());
        list.add(CustRoleEnum.COMMONCSUT.getCode());
        list.add(CustRoleEnum.GUARANTOR.getCode());
        List<CaseUpdateDetailDto>   detailDtoList= new ArrayList<>();
        for(int i=0;i<list.size();i++){
            CaseUpdateDetailDto  detailDto= new CaseUpdateDetailDto();
            CaseCustInfo caseCustInfo=caseCustInfoService.getOne(Wrappers.<CaseCustInfo>query().lambda()
                    .eq(CaseCustInfo::getApplyNo,applyNo)
                    .eq(CaseCustInfo::getCustRole,list.get(i)));
            if(ObjectUtils.isNotEmpty(caseCustInfo)){
                /**  个人客户信息详情  **/
                CaseCustIndividual caseCustIndividual = caseCustIndividualServicex.getOne(Wrappers.<CaseCustIndividual>query().lambda()
                        .eq(CaseCustIndividual::getCustId, caseCustInfo.getId()));
                detailDto.setId(caseCustInfo.getId());
                detailDto.setCustRole(list.get(i));
                detailDto.setDrivingLicenceNo(caseCustIndividual.getDrivingLicenceNo());
                detailDto.setDrivingType(caseCustIndividual.getDrivingType());
                detailDto.setFamilyIncome(caseCustIndividual.getOtherIncome());
                detailDto.setHighestEducation(caseCustIndividual.getHighestEducation());
                detailDto.setIndustryType(caseCustIndividual.getIndustryType());
                detailDto.setMaritalStatus(caseCustIndividual.getMaritalStatus());
                detailDto.setMonthlyIncome(caseCustIndividual.getMonthlyIncome());
                detailDto.setOutstandingLoan(caseCustIndividual.getOutstandingLoan());
                detailDto.setPosition(caseCustIndividual.getPosition());
                detailDto.setProfessionalType(caseCustIndividual.getProfessionalType());
                detailDto.setUnitName(caseCustIndividual.getUnitName());
                detailDto.setUnitTelPhone(caseCustIndividual.getUnitTelPhone());
                detailDto.setUnitType(caseCustIndividual.getUnitType());
                detailDto.setWorkAge(caseCustIndividual.getWorkAge());

                /**客户地址信息*/
                List<CaseCustAddress> caseCustAddressList=caseCustAddressService.list(
                        Wrappers.<CaseCustAddress>query().lambda().eq(CaseCustAddress::getCustId,caseCustInfo.getId())
                );
                List<CaseCustAddressDto> caseCustAddressDtoList=new ArrayList<>();
                if(CollectionUtil.isNotEmpty(caseCustAddressList)){
                    for(CaseCustAddress custAddress:caseCustAddressList){
                        CaseCustAddressDto  addressDto= new CaseCustAddressDto();
                        BeanUtil.copyProperties(custAddress,addressDto);
                        caseCustAddressDtoList.add(addressDto);
                    }
                }
                detailDto.setCaseCustAddressList(caseCustAddressDtoList);

                /**客户联系人信息*/
                List<CaseCustContact> caseCustContactList=caseCustContactService.list(
                        Wrappers.<CaseCustContact>query().lambda().eq(CaseCustContact::getCustId,caseCustInfo.getId().toString())
                );
                List<CaseCustContactDto> caseCustContactDtoList=new ArrayList<>();
                if(CollectionUtil.isNotEmpty(caseCustContactList)){
                    for(CaseCustContact custContact:caseCustContactList){
                        CaseCustContactDto  custContactDto= new CaseCustContactDto();
                        BeanUtil.copyProperties(custContact,custContactDto);
                        caseCustContactDtoList.add(custContactDto);
                    }
                }
                detailDto.setCaseCustContactList(caseCustContactDtoList);
            }
            detailDtoList.add(detailDto);
        }
        return detailDtoList;
    }

    /**
     * @Description 常规审核流程以及正式复议流程到达终审节点调用玄武反欺诈
     * @Author Peng_Jinbo
     * @Date 2020/9/2 19:06
     */
    private void checkFlowTypeWhenFirstNodeSubmit(NormalTaskSubmitVO submitVO){
        WorkProcessScheduleInfo info = submitVO.getWorkFlowInfo();
        WorkflowTypeEnum flowType = WorkflowTypeUtil.getType(info.getAfsFlowKey()).getApproveType();
        boolean first = WhetherEnum.YES.getCode().equals(info.getFirstTrail());
        boolean last = WhetherEnum.YES.getCode().equals(info.getLastTrail());
        if(first && !last) { // 多岗审核时首节点提交后调用玄武
            if (ProcessTypeEnum.GENERA_APPROVE == flowType
                    || ProcessTypeEnum.FORMAL_REVIEW == flowType) {
                GwtTortoiseAntiFraudCallStep callStep = GwtTortoiseAntiFraudCallStep.BEFORE_FINALLY_APPROVE_END;
                GwtTortoiseStartApproveType approveType = GwtTortoiseStartApproveType.NORMAL;
                if(ProcessTypeEnum.FORMAL_REVIEW == flowType){ // 复议标识
                    approveType = GwtTortoiseStartApproveType.REVIEW;
                }
                // 避免流程流转时事务未提交导致提供给玄武的数据为旧数据
                caseTortoiseService.safeDelaySignFraudHand(info.getApplyNo(), callStep, approveType);
            }
        }
    }
    /**
     * @description: 退回经销商时校验是否附条件核准
     * @author jiaqi.guo
     * @created 2020/10/11 16:19
     * @version 1.0
     */
    private void checkCondition(CaseApproveRecord caseApproveRecord){
        BigDecimal oldMonthPayAmt=this.getOldMonthPayAmt(caseApproveRecord.getApplyNo());
        FinCostDetails finCostDetails=caseCostInfoService.getOne(Wrappers.<FinCostDetails>query().lambda()
                .eq(FinCostDetails::getApplyNo,caseApproveRecord.getApplyNo())
                .eq(FinCostDetails::getCostType,CostTypeEnum.CARAMT.getCode()));
        if(oldMonthPayAmt.compareTo(finCostDetails.getMonthPayAmt())!=0){
            throw  new  AfsBaseException("当前案件存在附条件操作不允许退回!");
        }
    }
    /**
     * @description: 获取附条件核准冗余首期月供
     * @author jiaqi.guo
     * @created 2020/9/27 21:28
     * @version 1.0
     */
    public BigDecimal getOldMonthPayAmt(String applyNo) {
        //add by gjq 附条件核准留痕
        CaseRedundantInfo redundantInfo= redundantInfoService.getOne(Wrappers.<CaseRedundantInfo>query().lambda()
                .eq(StringUtils.isNotBlank(applyNo),CaseRedundantInfo::getApplyNo,applyNo));
        JSONObject jsonObject=null;
        BigDecimal oldMonthPayAmt=BigDecimal.ZERO;
        if(ObjectUtils.isNotEmpty(redundantInfo)){
            String conditionalApproval=redundantInfo.getConditionalApproval();
            if(StringUtils.isNotBlank(conditionalApproval)){
                jsonObject= JSONObject.parseObject(conditionalApproval);
            }
        }
        //融资信息
        JSONArray costDetailsList = jsonObject.getJSONArray("finCostDetailsList");
        if (ObjectUtils.isNotEmpty(costDetailsList) && costDetailsList.size() > 0) {
            for (FinCostDetails finCostDetails : costDetailsList.toJavaList(FinCostDetails.class)) {
                if(finCostDetails.getCostType().equals(CostTypeEnum.CARAMT.getCode())){
                    oldMonthPayAmt=oldMonthPayAmt.add(finCostDetails.getMonthPayAmt());
                }
            }

        }
        return oldMonthPayAmt;
    }

    /**
     * @Description 供定时任务调用，人员当日不上岗时，待审核案件回收至待分配任务池
     * @Author Peng_Jinbo
     * @Date 2020/10/12 16:36
     */
    public void cronNotOnlineTaskRecycle() {
        // 当前待分配的常规流程任务项
        List<WorkTaskPool> normalFlowPoolList = workTaskPoolService.listAllNormalFlowPool(AfsEnumUtil.key(BusinessStateInEnum.WAIT_CHECK), ProcessTypeEnum.GENERA_APPROVE.getCode());
        log.info("人员离岗流程回收任务 ==> START");
        if (CollectionUtil.isNotEmpty(normalFlowPoolList) || true) {

            LocalDate now = LocalDate.now();
            String year = now.getYear() + "";
            String month = StrUtil.padPre(now.getMonthValue() + "", 2, "0");
            String day = StrUtil.padPre(now.getDayOfMonth() + "", 2, "0");
            BaseHoliday currentHoliday = baseHolidayService.getOne(
                    Wrappers.<BaseHoliday>lambdaQuery()
                            .eq(BaseHoliday::getYear, year)
                            .eq(BaseHoliday::getMonth, month)
                            .eq(BaseHoliday::getDay, day)
            );

            // 默认工作日历
            boolean todayIsRestDay = Objects.isNull(currentHoliday) &&
                    StrUtil.equals(WorkFlag.REST_FLAG.getCode(), currentHoliday.getWorkFlagAm())
                    && StrUtil.equals(WorkFlag.REST_FLAG.getCode(), currentHoliday.getWorkFlagPm());

            Map<String, Boolean> staffTodayWorkFlagMap = opraHolidayService.list(
                    Wrappers.<OpraHoliday>lambdaQuery()
                            .eq(OpraHoliday::getYear, year)
                            .eq(OpraHoliday::getMonth, month)
                            .eq(OpraHoliday::getDay, day)
                            .orderByAsc(OpraHoliday::getCreateTime)
            ).stream().collect(Collectors.toMap(OpraHoliday::getLoginName,
                    oprHoliday ->
                            StrUtil.equals(WorkFlag.REST_FLAG.getCode(), oprHoliday.getWorkFlagAm())
                                    && StrUtil.equals(WorkFlag.REST_FLAG.getCode(), oprHoliday.getWorkFlagPm()),
                    (oldVal, newVal) -> newVal
            ));

            // 今日不上岗人员
            Set<String> notOnlineStaffNameSet = userCollocationService.list(
                    Wrappers.<UserCollocation>lambdaQuery()
                            .notLike(UserCollocation::getLoginName, "admin")
                            .eq(UserCollocation::getPostStatus, PostStatus.NO.getCode())
            )
                    .stream()
                    .filter(
                            user ->
                                    staffTodayWorkFlagMap.containsKey(user.getLoginName()) ? staffTodayWorkFlagMap.get(user.getLoginName()) : todayIsRestDay
                    )
                    .map(UserCollocation::getLoginName).collect(Collectors.toSet());

            log.info("人员离岗流程回收任务 ==> 今日不上岗人员名单：{}",notOnlineStaffNameSet);

            Map<String, WorkTaskPool> stageIdPoolMap = normalFlowPoolList.stream()
                    .filter(pool -> notOnlineStaffNameSet.contains(pool.getApproveStaff()))
                    .collect(Collectors.toMap(WorkTaskPool::getStageId, Function.identity()));

            Set<String> successStageIdSet = new HashSet<>();
            Set<String> successApplyNoSet = new HashSet<>();
            for (WorkTaskPool pool : stageIdPoolMap.values()) {
                try {
                    WorkFlowResponse flowResponse = cancelFlow(pool.getStageId(), "人员离岗监测，自动撤销当前人员下待审核案件", false);
                    afterSubmit(flowResponse);
                    successStageIdSet.add(pool.getStageId());
                    successApplyNoSet.add(pool.getApplyNo());
                    log.info("人员离岗流程回收任务 ==> 流程[{}]自动撤销成功", pool.getStageId());
                } catch (Exception e) {
                    log.warn("人员离岗流程回收任务 ==> 流程[{}]自动撤销失败：{}", pool.getStageId(), e.getMessage(), e);
                }
            }
            if (CollectionUtil.isNotEmpty(successStageIdSet)) {
                caseBaseInfoService.update(
                        Wrappers.<CaseBaseInfo>lambdaUpdate()
                                .in(CaseBaseInfo::getApplyNo, successApplyNoSet)
                                .set(CaseBaseInfo::getBusinessStateIn, AfsEnumUtil.key(BusinessStateInEnum.ALLOCATION))
                                .set(CaseBaseInfo::getFlowRecycleStatus, WhetherEnum.YES.getCode())
                );
            }
            Set<String> falidStageIdSet = stageIdPoolMap.keySet().stream().filter(stageId -> !successStageIdSet.contains(stageId)).collect(Collectors.toSet());
            log.info("人员离岗流程回收任务 ==> 案件流程回收成功共{}项：{}", successStageIdSet.size(), successStageIdSet);
            log.info("人员离岗流程回收任务 ==> 案件流程回收失败共{}项：{}", falidStageIdSet.size(), falidStageIdSet);
        } else {
            log.info("人员离岗流程回收任务 ==> 当前不存在可回收案件审批流程");
        }
        log.info("人员离岗流程回收任务 ==> END");
    }

}
